package com.lovely3x.jobservice.executors.extensions.downloader2.executor;

import android.support.annotation.NonNull;

import com.lovely3x.common.utils.ALog;
import com.lovely3x.jobservice.executors.TaskExecutor;
import com.lovely3x.jobservice.executors.extensions.downloader2.DownloadTask;
import com.lovely3x.jobservice.executors.extensions.downloader2.factory.DownloaderFactory;
import com.lovely3x.jobservice.serializer.TaskSerializer;
import com.lovely3x.jobservice.task.Progress;
import com.lovely3x.jobservice.task.Task;

import java.io.File;
import java.util.List;

/**
 * 下载任务执行器
 * Created by lovely3x on 16-2-3.
 */
public class DownloadTaskExecutor extends TaskExecutor.AbstractTaskExecutor implements Downloader2.DownloadProgressListener {
    /**
     * 单线程下载
     */
    public static final int SINGLE_DOWNLOAD_THREAD = 1;
    /**
     * 正常的下载线程数量
     */
    public static final int NORMAL_DOWNLOAD_THREAD = 3;
    /**
     * 最大的文件下载线程数量
     */
    public static final int MAX_DOWNLOAD_THREAD = 12;

    /**
     * 任务执行类型
     */
    public static final String EXECUTOR_TYPE = DownloaderFactory.TASK_EXECUTOR_TYPE;
    /**
     * 下载块表名
     */
    public static final String TAB_PARTS = "tab_download_task_parts";
    /**
     * 下载表任务名
     */
    public static final String DATA_TABLE = "tab_download_task_list";
    /**
     * 下载进度
     */
    public static final String TAB_PROGRESS = "tab_download_progress";

    /**
     * 进度对象
     */
    private final Progress PROGRESS = new DownloadProgress();

    /**
     * 下载器
     */
    private Downloader2 mDownloader;

    /**
     * 执行的结果 如果为null说明执行成功
     * 否则就是异常原因
     */
    private Exception executeResult;

    private Task mTask;

    @Override
    public Exception execute(Task task) {
        executeResult = null;
        this.mTask = task;
        mDownloader = new Downloader2();
        mDownloader.setDownloadProgressListener(this);

        //如果在开始时就失败了
        //就直接返回失败原因
        //这里的失败原因大致是
        //1，内存不足
        //2，网络连接失败
        //详见代码
        try {
            mDownloader.start((DownloadTask) task, PROGRESS, null);
        } catch (Exception e) {
            e.printStackTrace();
            return e;
        }

        synchronized (this) {
            try {
                wait();
            } catch (InterruptedException e) {
                return e;
            }
        }
        return executeResult;
    }


    @Override
    public Exception resume(Task task, Progress progress) {
        executeResult = null;

        if (!(task instanceof DownloadTask) || progress == null)
            return new NullPointerException("需要恢复的任务或进度对象为null");

        final DownloadTask downloadTask = (DownloadTask) task;

        if (progress.getState() == Progress.State.SUCCESSFUL) {
            File f = new File(downloadTask.storePath);
            if (f.exists() && f.length() == progress.getMax()) {
                return new IllegalStateException("任务已经完成");
            }
        }
        if (progress.getState() == Progress.State.EXECUTING)
            return new IllegalStateException("任务正在运行中，无需恢复。");

        final List<Part> parts = downloadTask.getDownloadParts();
        mTask = task;
        mDownloader = new Downloader2();
        mDownloader.setDownloadProgressListener(this);

        synchronized (PROGRESS) {
            PROGRESS.setState(Progress.State.EXECUTING);
        }
        try {
            mDownloader.start(downloadTask, PROGRESS, parts);
        } catch (Exception e) {
            e.printStackTrace();
            return e;
        }

        synchronized (this) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        return executeResult;
    }


    @Override
    public boolean remove() {
        try {
            if (mDownloader != null) {
                mDownloader.stop();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public Exception stop() {
        if (mDownloader == null) return new IllegalStateException();
        //无需停止
        if (PROGRESS.getState() == Progress.State.FAILURE)
            return new IllegalStateException("任务已经完成");
        if (PROGRESS.getState() == Progress.State.SUCCESSFUL)
            return new IllegalStateException("任务已经失败");
        try {
            mDownloader.stop();
            return null;
        } catch (Exception e) {
            return e;
        }
    }

    @Override
    public boolean handleable(Task task) {
        return task instanceof DownloadTask && EXECUTOR_TYPE.equals(task.getTaskType());
    }

    @NonNull
    @Override
    public Progress getProgress() {
        synchronized (PROGRESS) {
            return PROGRESS;
        }
    }

    @Override
    public void serialize(TaskSerializer serializer) {
        if (serializer != null && mTask != null) {
            serializer.serialize(mTask);
            serializer.serializeProgress(PROGRESS);
        }
    }

    @Override
    public void onStart(long taskWhat) {
        if (DEBUG) ALog.i(TAG, String.format("%d 任务开始下载 ", taskWhat));
        synchronized (PROGRESS) {
            PROGRESS.setState(Progress.State.EXECUTING);
        }

    }

    @Override
    public void onDoing(long taskWhat, long current, long max) {
        //if (DEBUG) ALog.i(TAG, String.format("%d 任务开始下载进度 总进度 %d 已下载 %d 进度比 %.5f ", taskWhat, max, current, current * 1f / max));
    }

    @Override
    public void onFailure(long taskWhat, Exception exception) {
        executeResult = exception;
        synchronized (PROGRESS) {
            PROGRESS.setState(Progress.State.FAILURE);
        }
        if (DEBUG) ALog.i(TAG, String.format("%d 下载失败 原因 %s ", taskWhat, exception));
        synchronized (this) {
            try {
                notifyAll();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onSuccessful(long taskWhat, long downloadBytes) {
        if (DEBUG) ALog.i(TAG, String.format("%d 下载成功 下载字节数 %d", taskWhat, downloadBytes));
        synchronized (PROGRESS) {
            PROGRESS.setState(Progress.State.SUCCESSFUL);
        }
        synchronized (this) {
            try {
                this.notifyAll();
            } catch (Exception e) {
                if (DEBUG) ALog.w(TAG, e);
            }
        }
    }
}
